#include <vtkActor.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
#include <vtkAutoInit.h>
#include <vtkDistanceWidget.h>
#include <vtkWidgetRepresentation.h>
#include <vtkDistanceRepresentation2D.h>
#include <vtkHandleRepresentation.h>
#include <vtkPointHandleRepresentation3D.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

namespace
{

  class vtkTimerCallback2 : public vtkCommand
  {
  public:
    vtkTimerCallback2() = default;
    ~vtkTimerCallback2() = default;

    int timerId = 0;
    static vtkTimerCallback2 *New()
    {
      vtkTimerCallback2 *cb = new vtkTimerCallback2;
      cb->TimerCount = 0;
      return cb;
    }
    virtual void Execute(vtkObject *caller, unsigned long eventId,
                         void *callData)
    {
      vtkRenderWindowInteractor *iren =
          dynamic_cast<vtkRenderWindowInteractor *>(caller);
      if (vtkCommand::TimerEvent == eventId)
      {
        ++this->TimerCount;
      }
      if (TimerCount < 36000)
      {
        actor->RotateZ(5);
        iren->GetRenderWindow()->Render();
      }
      else
      {
        iren->DestroyTimer();
      }
    }

  private:
    int TimerCount = 0;

  public:
    vtkActor *actor = nullptr;
  };

  class vtkClearDistance: public vtkCommand
  {
  public:
    static vtkClearDistance * New()
    {
      vtkClearDistance *cb = new vtkClearDistance;
      return cb;
    }
    virtual void Execute(vtkObject *caller, unsigned long eventId,
                         void *callData)
    {
      double pos[3] = {0, 0, 0};
      distanceWidget->GetDistanceRepresentation()->GetPoint1Representation()->SetWorldPosition(pos);
      distanceWidget->GetDistanceRepresentation()->GetPoint2Representation()->SetWorldPosition(pos);
    }
    vtkDistanceWidget * distanceWidget = nullptr;
  };
} // namespace

int main(int, char *[])
{
  vtkNew<vtkNamedColors> colors;

  // Create a sphere
  vtkNew<vtkSphereSource> sphereSource;
  sphereSource->SetCenter(0.0, 0.0, 0.0);
  sphereSource->SetRadius(1.0);
  sphereSource->SetThetaResolution(15);
  sphereSource->SetPhiResolution(15);
  sphereSource->Update();

  // Create a mapper and actor
  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputConnection(sphereSource->GetOutputPort());
  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);
  actor->RotateX(90);
  actor->GetProperty()->SetRepresentationToWireframe();

  // Create a renderer, render window, and interactor
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->AddRenderer(renderer);
  renderWindow->SetSize(640, 480);

  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);

  // Add the actor to the scene
  renderer->AddActor(actor);
  vtkSmartPointer<vtkDistanceWidget> distanceWidget = vtkSmartPointer<vtkDistanceWidget>::New();
  distanceWidget->SetInteractor(renderWindowInteractor);
  distanceWidget->CreateDefaultRepresentation();
  // 原第93行替换为以下内容：
  vtkDistanceRepresentation2D * distanceRepresentation = dynamic_cast<vtkDistanceRepresentation2D *>(distanceWidget->GetRepresentation());
  renderer->SetBackground(colors->GetColor3d("Seashell").GetData());
  // Render and interact
  renderWindow->SetWindowName("RotatingSphere");
  renderWindow->Render();

  distanceWidget->EnabledOn();
  // Initialize must be called prior to creating timer events.
  renderWindowInteractor->Initialize();

  // Sign up to receive TimerEvent
  vtkNew<vtkTimerCallback2> cb;
  cb->actor = actor;
  renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, cb);
  
  vtkNew<vtkClearDistance> clearDistance;
  clearDistance->distanceWidget = distanceWidget;
  distanceWidget->AddObserver(vtkCommand::LeftButtonDoubleClickEvent, clearDistance);
  int timerId = renderWindowInteractor->CreateRepeatingTimer(100);
  cb->timerId = timerId;

  // Start the interaction and timer
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}